import sys
import pickle
import getopt

from shore import *

class LeafArea:
    def __init__(self, data):
        self.data = data
        self.data_names = ('timestamp', 'leaf_n', 'a', 'l', 'w')

    def retrieve(self, r=0):
        run = r or len(self.data)
        prev_s = run - 1
        current_run_copy = {}
        for dn in self.data_names:
            current_run_copy[dn] = self.data[run][dn][:]
        while current_run_copy['leaf_n'][0] > 1:
            earliest_leaf = current_run_copy['leaf_n'][0]
            slice_ = self.data[prev_s]['leaf_n'].index(earliest_leaf)
            for dn in self.data_names:
                current_run_copy[dn] = self.data[prev_s][dn][0:slice_] + \
                                       current_run_copy[dn]
            prev_s -= 1
        return current_run_copy


def pickle_jar(jar, mode, cornichon=None):
    """Saves or retrieves to/from a pickle.  Returns data in open mode.

    Takes a file name to open (not a file object, a string).  When mode
    is 'pickle' or 'close', it expects data to write to the pickle file,
    and it does so opening the file in write mode, so any previous data
    is erased.
    """
    if mode in ('unpickle', 'open'):
        try:
            cukes = pickle.load(open(jar, 'r'))
        except IOError:
            cukes = None
        return cukes
    elif mode in ('pickle', 'close'):
        if not cornichon:
            e = 'Tried to add pickles to the jar but missed the cornichon!'
            raise ValueError, e
        pickle.dump(cornichon, open(jar, 'w'))


def reconstruct_full_data(la):
    full_data = {}
    for r in la.data:
        full_data[r] = la.retrieve(r)
    return full_data


def equalize_lengths(data, k=None):
    """Fills empties so all arrays have equal length; returns None.

    Given a dictionary with numbered keys containing dictionaries with
    key names specified in 'keys' and each containing a list, it
    extends shorter lists with as many -1's as necessary to be of equal
    length as one of the last key's list.  This way a matrix can be
    created from them shuch that:

    A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1
     2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2
     3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3
    -1, -1, -1, -1,  4,  4,  4,  4,  4,  4,  4,  4
    -1, -1, -1, -1,  5,  5,  5,  5,  5,  5,  5,  5
    -1, -1, -1, -1,  6,  6,  6,  6,  6,  6,  6,  6
    -1, -1, -1, -1, -1, -1, -1, -1,  7,  7,  7,  7
    -1, -1, -1, -1, -1, -1, -1, -1,  8,  8,  8,  8

    Assumptions are as follows:
      * each measurement set is either equal or longer than the
        previous set (e.g. increasing number of leaves)
      * no negative values in measurements (although this can obviously
        be customised as necessary)
      * uses the last measurement set as reference

    Makes writing columns with data sets of different lengths to a csv
    log file much simpler ;-)

    >>> m = {1: {'timestamp': [1, 2, 3],
    ...          'leaf_n': [1, 2, 3],
    ...          'w': [1, 2, 3],
    ...          'l': [1, 2, 3],
    ...          'a': [1, 2, 3]},
    ...      2: {'timestamp': [1, 2, 3, 4, 5, 6],
    ...          'leaf_n': [1, 2, 3, 4, 5, 6],
    ...          'w': [1, 2, 3, 4, 5, 6],
    ...          'l': [1, 2, 3, 4, 5, 6],
    ...          'a': [1, 2, 3, 4, 5, 6]},
    ...      3: {'timestamp': [1, 2, 3, 4, 5, 6, 7, 8],
    ...          'leaf_n': [1, 2, 3, 4, 5, 6, 7, 8],
    ...          'w': [1, 2, 3, 4, 5, 6, 7, 8],
    ...          'l': [1, 2, 3, 4, 5, 6, 7, 8],
    ...          'a': [1, 2, 3, 4, 5, 6, 7, 8]}}
    >>> m[1]['w']
    [1, 2, 3]
    >>> m[3]['l']
    [1, 2, 3, 4, 5, 6, 7, 8]
    >>> equalize_lengths(m)
    >>> m[1]['w']
    [1, 2, 3, -1, -1, -1, -1, -1]
    >>> m[2]['a']
    [1, 2, 3, 4, 5, 6, -1, -1]
    >>> m[3]['l']
    [1, 2, 3, 4, 5, 6, 7, 8]
    """
    keys = k or ('timestamp', 'leaf_n', 'w', 'l', 'a')
    runs = data.keys()
    latest_m_length = len(data[runs[-1]][a])
    for r in runs[:-1]:  # Skip last run
        for k in keys:
            len_diff = latest_m_length - len(data[r][k])
            data[r][k].extend([-1 for n in range(len_diff)])


def dump_measurements(data, file_=None):
    """
    """
    # XXX:2009-06-04:damosurfer: Getting better, measurements used to
    # assume weird order of [a][r][n], now changed to [r][a][n]
    # so runs are {1: {a: [n]...}, 2:, ... i:...}
    #
    # Added a measurement_runs in __reset__ to reflect this.
    #
    write = file_ and file_.write or sys.stdout.write
    r = len(data)
    run_range = range(1, r + 1)
    line_template = '%s\n' % ','.join(('%d,%d,%.3f,%.3f,%.5f',) * r)
    for n in range(len(data[r][a])):
        values = []
        temp_values = [[data[r]['timestamp'][n],
                        data[r][leaf_n][n],
                        data[r][w][n],
                        data[r][l][n],
                        data[r][a][n]]
                       for r in run_range]
        for v in temp_values:
            values.extend(v)
        temp_line = line_template % tuple(values)
        line = temp_line.replace('-1.00000', '') \
                        .replace('-1.000', '') \
                        .replace('-1', '')
        write(line)


def main(pickle_):
    pass


if __name__ == '__main__':
    short_opts = 'df:'
    long_opts = ['dump', 'file=']
    try:
        opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
    except getopt.GetoptError:
        opts = [(None, None)]
    for opt, arg in opts:
        if opt in ('-h', '--help'):
            usage()
        elif opt in ('-v', '--version'):
            version()
        elif opt in ('-f', '--file'):
            data = pickle_jar(arg, 'open')
            la = LeafArea(data)
    complete_data = reconstruct_full_data(la)
    equalize_lengths(complete_data)
    dump_measurements(complete_data)
